--[[
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

Detection for CVE-2015-6132/6133 expects PPT or PPSX

This lua script can be run standalone and verbosely on a Flash file with
echo "run()" | luajit -i <script name> <power pointfile>

Will Metcalf
Chris Wakelin
Francis Trudeau
--]]
susp_class = {
              {"\201\175\171\236\25\127\210\17\151\142\0\0\248\117\126\42","\110\219\124\210\109\174\207\17\150\184\68\69\83\84\0\0","\181\232\60\217\248\59\44\70\160\63\222\210\115\0\120\186",1,true,"CLSID"},
             }

require("zip")

function init (args)
    local needs = {}
    needs["http.response_body"] = tostring(true)
    return needs
end


--http://snippets.luacode.org/?p=snippets/String_to_Hex_String_68
function HexDumpString(str,spacer)
    return (
    string.gsub(str,"(.)",
    function (c)
        return string.format("%02X%s",string.byte(c), spacer or "\\")
    end)
    )
end

function match_strings(a,match_set,verbose)
    local rtn = 0
    local n,m
    local num_strings = #match_set - 3

    local match_num = match_set[num_strings+1]
    local plain = match_set[num_strings+2]
    local desc = match_set[num_strings+3]
    local cnt=0
    local fnd

   if verbose == 1 then print("Looking for " .. match_num .. " out of " .. num_strings .. " strings : " .. desc) end
    for n = 1, num_strings, 1 do
        m = match_set[n]
       if verbose == 1 then print("Looking for string " .. cnt .. " of " .. match_num .. " : " .. m) end
        fnd = string.find(a,m,1,plain)
        if fnd then
            cnt = cnt + 1
           if verbose == 1 then print("Found string " .. cnt .. " of " .. match_num .. " : " .. m) end
            if cnt == match_num then
                if verbose == 1 then print("Found " .. desc) end
                rtn = 1
                break
            end
        end
    end
    
    return rtn
end

function find_clsid(u,filename,verbose)
    local rtn = 0
    for l,s in pairs(susp_class) do
        if (verbose==1) then print("Looking for " .. s[#s]) end
        if match_strings(u,s,verbose) == 1 then
            rtn = 1
            if (verbose == 0) then
                break
            end
        end
    end
    if (verbose == 0) then
        if rtn == 1 then return 1 end
    end
    return rtn
end

function ppt_handler(t,verbose)
    rtn = 0
    tmpname = os.tmpname()
    
    tmp = io.open(tmpname,'w')
    tmp:write(t)
    tmp:close()

    z,err = zip.open(tmpname)
    local buffers = {}
    if z then
        for w in z:files() do
            if string.find(w.filename,"ppt/embeddings/oleObject",1,true) then
                f = z:open(w.filename);
                u = f:read("*all")
                f:close()
                if (verbose==1) then print("Checking " .. w.filename) end
                    rtn2 = find_clsid(u,w.filename,verbose)
                    if (verbose == 0) then
                        if rtn2 == 1 then return 1 end
                    end
                    if rtn2 == 1 then rtn = rtn2 end
                end
            end
    end
    if err then print(err) end
    if z then z:close() end
    os.remove(tmpname)
    return rtn
end

function common(t,o,verbose)
    rtn = 0
    if string.sub(t,1,4) == "PK\003\004" then
        rtn = ppt_handler(t,verbose)
    end
    return rtn 
end

function match(args)
    local t = tostring(args["http.response_body"])
    local o = args["offset"]
    return common(t,o,0)
end

function run()
  local f = io.open(arg[1])
  local t = f:read("*all")
  f:close()
  common(t,4,1)
end
